package redisdao

import (
	"context"
	"crypto/tls"
	"log"
	"strconv"
	"sync"
	"time"

	"gitcode.com/common_go/config"
	"github.com/go-redis/redis/v8"
)

func newRedisClient(server string, option redis.Options) *redis.Client {
	client := redis.NewClient(&redis.Options{
		Addr:        server,
		Password:    option.Password, // no password set
		DB:          option.DB,       // use default DB
		PoolSize:    option.PoolSize,
		IdleTimeout: option.IdleTimeout,
		ReadTimeout: option.ReadTimeout,
		MaxRetries:  option.MaxRetries,
		TLSConfig:   option.TLSConfig,

		MinIdleConns: 16,
	})

	_, err := client.Ping(context.Background()).Result()
	if err != nil {
		log.Printf("get redis connect error: %v, server:%v ", err, server)
	}

	return client
}

var initOnce sync.Once

var instance = struct {
	sync.RWMutex
	redisInstances map[string]*redis.Client
}{redisInstances: make(map[string]*redis.Client, 0)}

func Init() {
	initOnce.Do(func() {
		initRedis()
	})
}

func initRedis() {
	instance.redisInstances = make(map[string]*redis.Client, 0)

	confMapList := config.GetConfArrayMap("Redis")
	for k, v := range confMapList {
		options := redis.Options{
			Password:    "",
			DB:          0,
			PoolSize:    100,
			IdleTimeout: 240 * time.Second,
			ReadTimeout: 5 * time.Second,
			MaxRetries:  0,
		}
		if p := config.GetConf("RedisConfig", k+".poolsize"); p != "" {
			if rt, err := strconv.Atoi(p); err == nil {
				options.PoolSize = rt
			} else {
				log.Printf("poolsize strconv.Atoi(%+v) error:%v", p, err)
			}
		}
		if p := config.GetConf("RedisConfig", k+".db"); p != "" {
			if rt, err := strconv.Atoi(p); err == nil {
				options.DB = rt
			} else {
				log.Printf("db strconv.Atoi(%+v) error:%v", p, err)
			}
		}
		if p := config.GetConf("RedisConfig", k+".idletimeout"); p != "" {
			if rt, err := strconv.Atoi(p); err == nil {
				options.IdleTimeout = time.Second * time.Duration(rt)
			} else {
				log.Printf("idletimeout strconv.Atoi(%+v) error:%v", p, err)
			}
		}
		if p := config.GetConf("RedisConfig", k+".readtimeout"); p != "" {
			if rt, err := strconv.Atoi(p); err == nil {
				options.ReadTimeout = time.Second * time.Duration(rt)
			} else {
				log.Printf("readtimeout strconv.Atoi(%+v) error:%v", p, err)
			}
		}
		if p := config.GetConf("RedisConfig", k+".password"); p != "" {
			options.Password = p
		}
		if p := config.GetConf("RedisConfig", k+".tlsinsecureskip"); p != "" {
			options.TLSConfig = &tls.Config{InsecureSkipVerify: true}
		}
		if p := config.GetConf("RedisConfig", k+".maxretries"); p != "" {
			if rt, err := strconv.Atoi(p); err == nil {
				options.MaxRetries = rt
			} else {
				log.Printf("maxretries strconv.Atoi(%+v) error:%v", p, err)
			}
		}
		for _, s := range v {
			instance.redisInstances[k] = newRedisClient(s, options)
		}
	}
}

func getInstance(server string) *redis.Client {
	instance.RLock()
	ins, ok := instance.redisInstances[server]
	instance.RUnlock()
	if ok && ins != nil {
		return ins
	}

	return nil
}

func setInstance(server string, client *redis.Client) {
	instance.Lock()
	instance.redisInstances[server] = client
	instance.Unlock()
}
